123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- /*
- * Copyright 2016, 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 "RSAllocationUtils.h"
- #include "llvm/ADT/StringRef.h"
- #include "llvm/IR/Constants.h"
- #include "llvm/IR/GlobalVariable.h"
- #include "llvm/IR/Instructions.h"
- #include "llvm/IR/Module.h"
- #include "llvm/Support/Debug.h"
- #include "llvm/Support/raw_ostream.h"
- #include "cxxabi.h"
- #include <sstream>
- #include <unordered_map>
- #define DEBUG_TYPE "rs2spirv-rs-allocation-utils"
- using namespace llvm;
- namespace rs2spirv {
- bool isRSAllocation(const GlobalVariable &GV) {
- auto *PT = cast<PointerType>(GV.getType());
- DEBUG(PT->dump());
- auto *VT = PT->getElementType();
- DEBUG(VT->dump());
- std::string TypeName;
- raw_string_ostream RSO(TypeName);
- VT->print(RSO);
- RSO.str(); // Force flush.
- DEBUG(dbgs() << "TypeName: " << TypeName << '\n');
- return TypeName.find("struct.rs_allocation") != std::string::npos;
- }
- bool getRSAllocationInfo(Module &M, SmallVectorImpl<RSAllocationInfo> &Allocs) {
- DEBUG(dbgs() << "getRSAllocationInfo\n");
- for (auto &GV : M.globals()) {
- if (GV.isDeclaration() || !isRSAllocation(GV))
- continue;
- Allocs.push_back({'%' + GV.getName().str(), None, &GV, -1});
- }
- return true;
- }
- // Collect Allocation access calls into the Calls
- // Also update Allocs with assigned ID.
- // After calling this function, Allocs would contain the mapping from
- // GV name to the corresponding ID.
- bool getRSAllocAccesses(SmallVectorImpl<RSAllocationInfo> &Allocs,
- SmallVectorImpl<RSAllocationCallInfo> &Calls) {
- DEBUG(dbgs() << "getRSGEATCalls\n");
- DEBUG(dbgs() << "\n\n~~~~~~~~~~~~~~~~~~~~~\n\n");
- std::unordered_map<const Value *, const GlobalVariable *> Mapping;
- int id_assigned = 0;
- for (auto &A : Allocs) {
- auto *GV = A.GlobalVar;
- std::vector<User *> WorkList(GV->user_begin(), GV->user_end());
- size_t Idx = 0;
- while (Idx < WorkList.size()) {
- auto *U = WorkList[Idx];
- DEBUG(dbgs() << "Visiting ");
- DEBUG(U->dump());
- ++Idx;
- auto It = Mapping.find(U);
- if (It != Mapping.end()) {
- if (It->second == GV) {
- continue;
- } else {
- errs() << "Duplicate global mapping discovered!\n";
- errs() << "\nGlobal: ";
- GV->print(errs());
- errs() << "\nExisting mapping: ";
- It->second->print(errs());
- errs() << "\nUser: ";
- U->print(errs());
- errs() << '\n';
- return false;
- }
- }
- Mapping[U] = GV;
- DEBUG(dbgs() << "New mapping: ");
- DEBUG(U->print(dbgs()));
- DEBUG(dbgs() << " -> " << GV->getName() << '\n');
- if (auto *FCall = dyn_cast<CallInst>(U)) {
- if (auto *F = FCall->getCalledFunction()) {
- const auto FName = F->getName();
- DEBUG(dbgs() << "Discovered function call to : " << FName << '\n');
- // Treat memcpy as moves for the purpose of this analysis
- if (FName.startswith("llvm.memcpy")) {
- assert(FCall->getNumArgOperands() > 0);
- Value *CopyDest = FCall->getArgOperand(0);
- // We are interested in the users of the dest operand of
- // memcpy here
- Value *LocalCopy = CopyDest->stripPointerCasts();
- User *NewU = dyn_cast<User>(LocalCopy);
- assert(NewU);
- WorkList.push_back(NewU);
- continue;
- }
- char *demangled = __cxxabiv1::__cxa_demangle(
- FName.str().c_str(), nullptr, nullptr, nullptr);
- if (!demangled)
- continue;
- const StringRef DemangledNameRef(demangled);
- DEBUG(dbgs() << "Demangled name: " << DemangledNameRef << '\n');
- const StringRef GEAPrefix = "rsGetElementAt_";
- const StringRef SEAPrefix = "rsSetElementAt_";
- const StringRef DIMXPrefix = "rsAllocationGetDimX";
- assert(GEAPrefix.size() == SEAPrefix.size());
- const bool IsGEA = DemangledNameRef.startswith(GEAPrefix);
- const bool IsSEA = DemangledNameRef.startswith(SEAPrefix);
- const bool IsDIMX = DemangledNameRef.startswith(DIMXPrefix);
- assert(IsGEA || IsSEA || IsDIMX);
- if (!A.hasID()) {
- A.assignID(id_assigned++);
- }
- if (IsGEA || IsSEA) {
- DEBUG(dbgs() << "Found rsAlloc function!\n");
- const auto Kind =
- IsGEA ? RSAllocAccessKind::GEA : RSAllocAccessKind::SEA;
- const auto RSElementTy =
- DemangledNameRef.drop_front(GEAPrefix.size());
- Calls.push_back({A, FCall, Kind, RSElementTy.str()});
- continue;
- } else if (DemangledNameRef.startswith(GEAPrefix.drop_back()) ||
- DemangledNameRef.startswith(SEAPrefix.drop_back())) {
- errs() << "Untyped accesses to global rs_allocations are not "
- "supported.\n";
- return false;
- } else if (IsDIMX) {
- DEBUG(dbgs() << "Found rsAllocationGetDimX function!\n");
- const auto Kind = RSAllocAccessKind::DIMX;
- Calls.push_back({A, FCall, Kind, ""});
- }
- }
- }
- // TODO: Consider using set-like container to reduce computational
- // complexity.
- for (auto *NewU : U->users())
- if (std::find(WorkList.begin(), WorkList.end(), NewU) == WorkList.end())
- WorkList.push_back(NewU);
- }
- }
- std::unordered_map<const GlobalVariable *, std::string> GVAccessTypes;
- for (auto &Access : Calls) {
- auto AccessElemTyIt = GVAccessTypes.find(Access.RSAlloc.GlobalVar);
- if (AccessElemTyIt != GVAccessTypes.end() &&
- AccessElemTyIt->second != Access.RSElementTy) {
- errs() << "Could not infere element type for: ";
- Access.RSAlloc.GlobalVar->print(errs());
- errs() << '\n';
- return false;
- } else if (AccessElemTyIt == GVAccessTypes.end()) {
- GVAccessTypes.emplace(Access.RSAlloc.GlobalVar, Access.RSElementTy);
- Access.RSAlloc.RSElementType = Access.RSElementTy;
- }
- }
- DEBUG(dbgs() << "\n\n~~~~~~~~~~~~~~~~~~~~~\n\n");
- return true;
- }
- bool solidifyRSAllocAccess(Module &M, RSAllocationCallInfo CallInfo) {
- DEBUG(dbgs() << "solidifyRSAllocAccess " << CallInfo.RSAlloc.VarName << '\n');
- auto *FCall = CallInfo.FCall;
- auto *Fun = FCall->getCalledFunction();
- assert(Fun);
- StringRef FName;
- if (CallInfo.Kind == RSAllocAccessKind::DIMX)
- FName = "rsAllocationGetDimX";
- else
- FName = Fun->getName();
- std::ostringstream OSS;
- OSS << "__rsov_" << FName.str();
- // Make up uint32_t F(uint32_t)
- Type *UInt32Ty = IntegerType::get(M.getContext(), 32);
- auto *NewFT = FunctionType::get(UInt32Ty, ArrayRef<Type *>(UInt32Ty), false);
- auto *NewF = Function::Create(NewFT, // Fun->getFunctionType(),
- Function::ExternalLinkage, OSS.str(), &M);
- FCall->setCalledFunction(NewF);
- FCall->setArgOperand(0, ConstantInt::get(UInt32Ty, 0, false));
- NewF->setAttributes(Fun->getAttributes());
- DEBUG(M.dump());
- return true;
- }
- } // namespace rs2spirv
|