222 строки
7.2 KiB
C++
222 строки
7.2 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// DxilExportMap.cpp //
|
|
// Copyright (C) Microsoft Corporation. All rights reserved. //
|
|
// This file is distributed under the University of Illinois Open Source //
|
|
// License. See LICENSE.TXT for details. //
|
|
// //
|
|
// dxilutil::ExportMap for handling -exports option. //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "dxc/HLSL/DxilExportMap.h"
|
|
#include "dxc/DXIL/DxilTypeSystem.h"
|
|
#include "dxc/DXIL/DxilUtil.h"
|
|
#include "dxc/Support/Global.h"
|
|
#include "llvm/ADT/DenseMap.h"
|
|
#include "llvm/ADT/DenseSet.h"
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/ADT/StringSet.h"
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include <set>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
using namespace llvm;
|
|
using namespace hlsl;
|
|
|
|
namespace hlsl {
|
|
namespace dxilutil {
|
|
|
|
void ExportMap::clear() { m_ExportMap.clear(); }
|
|
bool ExportMap::empty() const { return m_ExportMap.empty(); }
|
|
|
|
bool ExportMap::ParseExports(const std::vector<std::string> &exportOpts,
|
|
llvm::raw_ostream &errors) {
|
|
for (auto &str : exportOpts) {
|
|
llvm::StringRef exports = StoreString(str);
|
|
size_t start = 0;
|
|
size_t end = llvm::StringRef::npos;
|
|
// def1;def2;...
|
|
while (true) {
|
|
end = exports.find_first_of(';', start);
|
|
llvm::StringRef exportDef = exports.slice(start, end);
|
|
|
|
// def: export1[[,export2,...]=internal]
|
|
llvm::StringRef internalName = exportDef;
|
|
size_t equals = exportDef.find_first_of('=');
|
|
if (equals != llvm::StringRef::npos) {
|
|
internalName = exportDef.substr(equals + 1);
|
|
size_t exportStart = 0;
|
|
while (true) {
|
|
size_t comma = exportDef.find_first_of(',', exportStart);
|
|
if (comma == llvm::StringRef::npos || comma > equals)
|
|
break;
|
|
if (exportStart < comma)
|
|
Add(exportDef.slice(exportStart, comma), internalName);
|
|
exportStart = comma + 1;
|
|
}
|
|
if (exportStart < equals)
|
|
Add(exportDef.slice(exportStart, equals), internalName);
|
|
} else {
|
|
Add(internalName);
|
|
}
|
|
|
|
if (equals == 0 || internalName.empty()) {
|
|
errors << "Invalid syntax for -exports: '" << exportDef
|
|
<< "'. Syntax is: export1[[,export2,...]=internal][;...]";
|
|
return false;
|
|
}
|
|
if (end == llvm::StringRef::npos)
|
|
break;
|
|
start = end + 1;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void ExportMap::Add(llvm::StringRef exportName, llvm::StringRef internalName) {
|
|
// Incoming strings may be escaped (because they originally come from
|
|
// arguments) Unescape them here, if necessary
|
|
if (exportName.startswith("\\")) {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
PrintUnescapedString(exportName, os);
|
|
exportName = StoreString(os.str());
|
|
}
|
|
if (internalName.startswith("\\")) {
|
|
std::string str;
|
|
llvm::raw_string_ostream os(str);
|
|
PrintUnescapedString(internalName, os);
|
|
internalName = StoreString(os.str());
|
|
}
|
|
|
|
if (internalName.empty())
|
|
internalName = exportName;
|
|
exportName = DemangleFunctionName(exportName);
|
|
m_ExportMap[internalName].insert(exportName);
|
|
}
|
|
|
|
ExportMap::const_iterator
|
|
ExportMap::GetExportsByName(llvm::StringRef Name) const {
|
|
ExportMap::const_iterator it = m_ExportMap.find(Name);
|
|
StringRef unmangled = DemangleFunctionName(Name);
|
|
if (it == end()) {
|
|
if (Name.startswith(ManglingPrefix)) {
|
|
it = m_ExportMap.find(unmangled);
|
|
} else if (Name.startswith(EntryPrefix)) {
|
|
it = m_ExportMap.find(Name.substr(strlen(EntryPrefix)));
|
|
}
|
|
}
|
|
return it;
|
|
}
|
|
|
|
bool ExportMap::IsExported(llvm::StringRef original) const {
|
|
if (m_ExportMap.empty())
|
|
return true;
|
|
return GetExportsByName(original) != end();
|
|
}
|
|
|
|
void ExportMap::BeginProcessing() {
|
|
m_ExportNames.clear();
|
|
m_NameCollisions.clear();
|
|
m_UnusedExports.clear();
|
|
for (auto &it : m_ExportMap) {
|
|
m_UnusedExports.emplace(it.getKey());
|
|
}
|
|
}
|
|
|
|
bool ExportMap::ProcessFunction(llvm::Function *F,
|
|
bool collisionAvoidanceRenaming) {
|
|
// Skip if already added. This can happen due to patch constant functions.
|
|
if (m_RenameMap.find(F) != m_RenameMap.end())
|
|
return true;
|
|
|
|
StringRef originalName = F->getName();
|
|
StringRef unmangled = DemangleFunctionName(originalName);
|
|
auto it = GetExportsByName(F->getName());
|
|
|
|
// Early out if not exported, and do optional collision avoidance
|
|
if (it == end()) {
|
|
F->setLinkage(GlobalValue::LinkageTypes::InternalLinkage);
|
|
if (collisionAvoidanceRenaming) {
|
|
std::string internalName = (Twine("internal.") + unmangled).str();
|
|
internalName = dxilutil::ReplaceFunctionName(originalName, internalName);
|
|
F->setName(internalName);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
F->setLinkage(GlobalValue::LinkageTypes::ExternalLinkage);
|
|
|
|
// Add entry to m_RenameMap:
|
|
auto &renames = m_RenameMap[F];
|
|
const llvm::StringSet<> &exportRenames = it->getValue();
|
|
llvm::StringRef internalName = it->getKey();
|
|
|
|
// mark export used
|
|
UseExport(internalName);
|
|
|
|
// Add identity first
|
|
auto itIdentity = exportRenames.find(unmangled);
|
|
if (exportRenames.empty() || itIdentity != exportRenames.end()) {
|
|
if (exportRenames.size() > 1)
|
|
renames.insert(originalName);
|
|
ExportName(originalName);
|
|
} else if (collisionAvoidanceRenaming) {
|
|
// do optional collision avoidance for exports being renamed
|
|
std::string tempName = (Twine("temp.") + unmangled).str();
|
|
tempName = dxilutil::ReplaceFunctionName(originalName, tempName);
|
|
F->setName(tempName);
|
|
}
|
|
|
|
for (auto itName = exportRenames.begin(); itName != exportRenames.end();
|
|
itName++) {
|
|
// Now add actual renames
|
|
if (itName != itIdentity) {
|
|
StringRef newName = StoreString(
|
|
dxilutil::ReplaceFunctionName(F->getName(), itName->getKey()));
|
|
renames.insert(newName);
|
|
ExportName(newName);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void ExportMap::RegisterExportedFunction(llvm::Function *F) {
|
|
// Skip if already added
|
|
if (m_RenameMap.find(F) != m_RenameMap.end())
|
|
return;
|
|
F->setLinkage(GlobalValue::LinkageTypes::ExternalLinkage);
|
|
NameSet &renames = m_RenameMap[F];
|
|
(void)(renames); // Don't actually add anything
|
|
ExportName(F->getName());
|
|
}
|
|
|
|
void ExportMap::UseExport(llvm::StringRef internalName) {
|
|
auto it = m_UnusedExports.find(internalName);
|
|
if (it != m_UnusedExports.end())
|
|
m_UnusedExports.erase(it);
|
|
}
|
|
void ExportMap::ExportName(llvm::StringRef exportName) {
|
|
auto result = m_ExportNames.insert(exportName);
|
|
if (!result.second) {
|
|
// Already present, report collision
|
|
m_NameCollisions.insert(exportName);
|
|
}
|
|
}
|
|
|
|
bool ExportMap::EndProcessing() const {
|
|
return m_UnusedExports.empty() && m_NameCollisions.empty();
|
|
}
|
|
|
|
llvm::StringRef ExportMap::StoreString(llvm::StringRef str) {
|
|
return *m_StringStorage.insert(str).first;
|
|
}
|
|
|
|
} // namespace dxilutil
|
|
} // namespace hlsl
|