C++程序  |  135行  |  3.7 KB

/*
 * Copyright 2017, The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "GlobalAllocPass.h"

#include "Context.h"
#include "RSAllocationUtils.h"

#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"

#define DEBUG_TYPE "rs2spirv-global-alloc"

using namespace llvm;

namespace rs2spirv {

namespace {
bool collectGlobalAllocs(Module &M,
                         SmallVectorImpl<GlobalVariable *> &GlobalAllocs) {
  for (auto &GV : M.globals()) {
    if (!isRSAllocation(GV))
      continue;

    DEBUG(GV.dump());
    GlobalAllocs.push_back(&GV);
  }

  return !GlobalAllocs.empty();
}

//
// This pass would enumerate used global rs_allocations (TBD) and
// lowers calls to accessors of the following type:
//
//    rsGetAllocationDimX(g)
//
// to
//
//    __rsov_rsGetAllocationDimX(some uninque constant identifying g) */
//
// Note the __rsov_* variant is used as a marker for another SPIRIT
// transformations (see GlobalAllocSPIRITPass.cpp) to expand them into
// SPIR-V instructions that loads the metadata.
//
class GlobalAllocPass : public ModulePass {
public:
  static char ID;
  GlobalAllocPass()
      : ModulePass(ID), Allocs(Context::getInstance().getGlobalAllocs()) {}

  const char *getPassName() const override { return "GlobalAllocPass"; }

  bool runOnModule(Module &M) override {
    DEBUG(dbgs() << "RS2SPIRVGlobalAllocPass\n");
    DEBUG(M.dump());

    SmallVector<GlobalVariable *, 8> GlobalAllocs;
    const bool CollectRes = collectGlobalAllocs(M, GlobalAllocs);
    if (!CollectRes)
      return false; // Module not modified.

    SmallVector<RSAllocationCallInfo, 8> Calls;
    getRSAllocationInfo(M, Allocs);
    getRSAllocAccesses(Allocs, Calls);

    // Lower the found accessors
    for (auto &C : Calls) {
      assert(C.Kind == RSAllocAccessKind::DIMX &&
             "Unsupported type of accessor call types");
      solidifyRSAllocAccess(M, C);
    }
    // Return true, as the pass modifies module.
    DEBUG(dbgs() << "RS2SPIRVGlobalAllocPass end\n");
    return true;
  }

private:
  SmallVectorImpl<RSAllocationInfo> &Allocs;
};

// A simple pass to remove all global allocations forcibly
class RemoveAllGlobalAllocPass : public ModulePass {
public:
  static char ID;
  RemoveAllGlobalAllocPass() : ModulePass(ID) {}
  const char *getPassName() const override {
    return "RemoveAllGlobalAllocPass";
  }

  bool runOnModule(Module &M) override {
    DEBUG(dbgs() << "RemoveAllGlobalAllocPass\n");
    DEBUG(M.dump());

    SmallVector<GlobalVariable *, 8> GlobalAllocs;
    const bool CollectRes = collectGlobalAllocs(M, GlobalAllocs);
    if (!CollectRes)
      return false; // Module not modified.
    // Remove global allocations
    for (auto *G : GlobalAllocs) {
      G->eraseFromParent();
    }
    DEBUG(dbgs() << "RemoveAllGlobalAllocPass end\n");
    DEBUG(M.dump());
    // Return true, as the pass modifies module.
    return true;
  }
};

} // namespace
char GlobalAllocPass::ID = 0;
char RemoveAllGlobalAllocPass::ID = 0;

ModulePass *createRemoveAllGlobalAllocPass() {
  return new RemoveAllGlobalAllocPass();
}
ModulePass *createGlobalAllocPass() { return new GlobalAllocPass(); }

} // namespace rs2spirv