/
redgpu
/
clspv
Обзор
Документация
Войти
/
redgpu
/
clspv
Код
Запросы
0
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
lib/HideConstantLoadsPass.cpp
195 строк
5 KB
alan-baker
Support global type-mangled pod args in push constants (#588)
21 май 2020, 17:09
Не верифицирован
21 май 2020, 17:09
6a3930b
Код
Авторство
О чём код?
// Copyright 2017 The Clspv Authors. All rights reserved. // // 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 <string> #include "llvm/ADT/DenseMap.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" #include "llvm/Pass.h" #include "llvm/Support/raw_ostream.h" #include "clspv/AddressSpace.h" #include "Passes.h" using namespace llvm; using std::string; #define DEBUG_TYPE "hideconstantloads" namespace { const char *kWrapFunctionPrefix = "clspv.wrap_constant_load."; class HideConstantLoadsPass : public ModulePass { public: static char ID; HideConstantLoadsPass() : ModulePass(ID) {} bool runOnModule(Module &M) override; private: // Return the name for the wrap function for the given type. string &WrapFunctionNameForType(Type *type) { auto where = function_for_type_.find(type); if (where == function_for_type_.end()) { // Insert it. auto &result = function_for_type_[type] = string(kWrapFunctionPrefix) + std::to_string(function_for_type_.size()); return result; } else { return where->second; } } // Maps a loaded type to the name of the wrap function for that type. DenseMap<Type *, string> function_for_type_; }; } // namespace char HideConstantLoadsPass::ID = 0; INITIALIZE_PASS(HideConstantLoadsPass, "HideConstantLoads", "Hide loads from __constant and push constant memory", false, false) namespace clspv { llvm::ModulePass *createHideConstantLoadsPass() { return new HideConstantLoadsPass(); } } // namespace clspv bool HideConstantLoadsPass::runOnModule(Module &M) { bool Changed = false; SmallVector<LoadInst *, 16> WorkList; for (Function &F : M) { for (BasicBlock &BB : F) { for (Instruction &I : BB) { if (LoadInst *load = dyn_cast<LoadInst>(&I)) { if (clspv::AddressSpace::Constant == load->getPointerAddressSpace() || clspv::AddressSpace::PushConstant == load->getPointerAddressSpace()) { WorkList.push_back(load); } } } } } if (WorkList.size() == 0) { return Changed; } for (LoadInst *load : WorkList) { Changed = true; auto loadedTy = load->getType(); // The wrap function conceptually maps the loaded value to itself. const string &fn_name = WrapFunctionNameForType(loadedTy); Function *fn = M.getFunction(fn_name); if (!fn) { // Make the function. FunctionType *fnTy = FunctionType::get(loadedTy, {loadedTy}, false); auto fn_constant = M.getOrInsertFunction(fn_name, fnTy); fn = cast<Function>(fn_constant.getCallee()); fn->addFnAttr(Attribute::ReadOnly); } // Wrap the load auto call = CallInst::Create(fn, {load}); call->insertAfter(load); // Replace other uses of the load with the result of the wrap call. { SmallVector<User *, 16> ToReplaceIn; for (auto &use : load->uses()) { User *user = use.getUser(); ToReplaceIn.push_back(user); } for (auto *user : ToReplaceIn) { if (dyn_cast<CallInst>(user) != call) { user->replaceUsesOfWith(load, call); } } } } return Changed; } namespace { class UnhideConstantLoadsPass : public ModulePass { public: static char ID; UnhideConstantLoadsPass() : ModulePass(ID) {} bool runOnModule(Module &M) override; private: // Maps a loaded type to the name of the wrap function for that type. DenseMap<Type *, string> function_for_type_; }; } // namespace char UnhideConstantLoadsPass::ID = 0; INITIALIZE_PASS(UnhideConstantLoadsPass, "UnhideConstantLoads", "Unhide loads from __constant and push constant memory", false, false) namespace clspv { llvm::ModulePass *createUnhideConstantLoadsPass() { return new UnhideConstantLoadsPass(); } } // namespace clspv bool UnhideConstantLoadsPass::runOnModule(Module &M) { bool Changed = false; SmallVector<Function *, 16> WorkList; for (auto &F : M.getFunctionList()) { if (F.getName().startswith(kWrapFunctionPrefix)) { WorkList.push_back(&F); } } if (WorkList.size() == 0) return Changed; SmallVector<CallInst *, 16> RemoveList; for (auto *F : WorkList) { for (auto &use : F->uses()) { if (auto *call = dyn_cast<CallInst>(use.getUser())) { assert(call->getNumArgOperands() == 1); auto *load = call->getArgOperand(0); call->replaceAllUsesWith(load); RemoveList.push_back(call); } } } for (auto *call : RemoveList) { call->eraseFromParent(); } for (auto *F : WorkList) { F->eraseFromParent(); } return Changed; }