Index: include/llvm/InitializePasses.h =================================================================== --- include/llvm/InitializePasses.h +++ include/llvm/InitializePasses.h @@ -284,6 +284,7 @@ void initializeStackMapLivenessPass(PassRegistry&); void initializeMachineCombinerPass(PassRegistry &); void initializeLoadCombinePass(PassRegistry&); +void initializeRewriteSymbolsPass(PassRegistry&); } #endif Index: include/llvm/LinkAllPasses.h =================================================================== --- include/llvm/LinkAllPasses.h +++ include/llvm/LinkAllPasses.h @@ -163,6 +163,7 @@ (void) llvm::createPartiallyInlineLibCallsPass(); (void) llvm::createScalarizerPass(); (void) llvm::createSeparateConstOffsetFromGEPPass(); + (void) llvm::createRewriteSymbolsPass(); (void)new llvm::IntervalPartition(); (void)new llvm::FindUsedTypes(); Index: include/llvm/Transforms/Utils/SymbolRewriter.h =================================================================== --- /dev/null +++ include/llvm/Transforms/Utils/SymbolRewriter.h @@ -0,0 +1,268 @@ +//===-- SymbolRewriter.h - Symbol Rewriting Pass ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the prototypes and definitions related to the Symbol +// Rewriter pass. +// +// The Symbol Rewriter pass takes a set of rewrite descriptors which define +// transformations for symbol names. These can be either single name to name +// trnsformation or more broad regular expression based transformations. +// +// All the functions are re-written at the IR level. The Symbol Rewriter itself +// is exposed as a module level pass. All symbols at the module level are +// iterated. For any matching symbol, the requested transformation is applied, +// updating references to it as well (a la RAUW). The resulting binary will +// only contain the rewritten symbols. +// +// By performing this operation in the compiler, we are able to catch symbols +// that would otherwise not be possible to catch (e.g. inlined symbols). +// +// This makes it possible to cleanly transform symbols without resorting to +// overly-complex macro tricks and the pre-processor. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_UTILS_SYMBOL_REWRITER_H +#define LLVM_TRANSFORMS_UTILS_SYMBOL_REWRITER_H + +#include "llvm/ADT/ilist.h" +#include "llvm/ADT/ilist_node.h" + +namespace llvm { +class MemoryBuffer; + +namespace yaml { +class KeyValueNode; +class MappingNode; +class ScalarNode; +class Stream; +} + +namespace SymbolRewriter { +/// RewriteDescriptor - the basic entity representing a rewrite operation. It +/// serves as the base class for any rewrite descriptor. It has a certain set +/// of +/// specializations which describe a particular rewrite. +/// +/// The RewriteMapParser can be used to parse a mapping file that provides the +/// mapping for rewriting the symbols. The descriptors individually describe +/// whether to rewrite a function, global variable, or global alias. Each of +/// these can be selected either by explicitly providing a name for the ones to +/// be rewritten or providing a (posix compatible) regular expression that will +/// select the symbols to rewrite. This descriptor list is passed to the +/// SymbolRewriter pass. +class RewriteDescriptor : public ilist_node { + RewriteDescriptor(const RewriteDescriptor &) LLVM_DELETED_FUNCTION; + + const RewriteDescriptor & + operator=(const RewriteDescriptor &) LLVM_DELETED_FUNCTION; + +public: + enum class RewriteDescriptorType { + Invalid, /// invalid + Function, /// function - descriptor rewrites a function + GlobalVariable, /// global variable - descriptor rewrites a global variable + NamedAlias, /// named alias - descriptor rewrites a global alias + }; + + virtual ~RewriteDescriptor() {} + + RewriteDescriptorType getType() const { return Type; } + + virtual bool performOnModule(Module &M) = 0; + +protected: + explicit RewriteDescriptor(RewriteDescriptorType T) : Type(T) {} + +private: + const RewriteDescriptorType Type; +}; + +/// ExplicitRewriteFunctionDescriptor - represents a rewrite for an explicitly +/// named (function) symbol. Both the source function name and target function +/// name of the transformation are explicitly spelt out. +class ExplicitRewriteFunctionDescriptor : public RewriteDescriptor { +public: + const std::string Source; + const std::string Target; + + ExplicitRewriteFunctionDescriptor(StringRef S, StringRef T, const bool Naked) + : RewriteDescriptor(RewriteDescriptorType::Function), + Source(Naked ? StringRef("\01" + S.str()) : S), Target(T) {} + + bool performOnModule(Module &M) override; + + static bool classof(const RewriteDescriptor *RD) { + return RD->getType() == RewriteDescriptorType::Function; + } +}; + +/// PatternRewriteFunctionDescriptor - represents a rewrite for a regular +/// expression based pattern for functions. A pattern for the function name is +/// provided and a transformation for that pattern to determine the target +/// function name create the rewrite rule. +class PatternRewriteFunctionDescriptor : public RewriteDescriptor { +public: + const std::string Pattern; + const std::string Transform; + + PatternRewriteFunctionDescriptor(StringRef P, StringRef T) + : RewriteDescriptor(RewriteDescriptorType::Function), Pattern(P), + Transform(T) {} + + bool performOnModule(Module &M) override; + + static bool classof(const RewriteDescriptor *RD) { + return RD->getType() == RewriteDescriptorType::Function; + } +}; + +/// ExplicitRewriteGlobalVariableDescriptor - represents a rewrite for an +/// explicitly named (global variable) symbol. Both the source variable name +/// and +/// target variable name are spelt out. This applies only to module level +/// variables. +class ExplicitRewriteGlobalVariableDescriptor : public RewriteDescriptor { +public: + const std::string Source; + const std::string Target; + + ExplicitRewriteGlobalVariableDescriptor(StringRef S, StringRef T) + : RewriteDescriptor(RewriteDescriptorType::GlobalVariable), Source(S), + Target(T) {} + + bool performOnModule(Module &M) override; + + static bool classof(const RewriteDescriptor *RD) { + return RD->getType() == RewriteDescriptorType::GlobalVariable; + } +}; + +/// PatternRewriteGlobalVariableDescriptor - represents a rewrite for a global +/// variable based upon a matching pattern. Each global variable matching the +/// provided pattern will be transformed as described in the transformation +/// pattern for the target. Applies only to module level variables. +class PatternRewriteGlobalVariableDescriptor : public RewriteDescriptor { +public: + const std::string Pattern; + const std::string Transform; + + PatternRewriteGlobalVariableDescriptor(StringRef P, StringRef T) + : RewriteDescriptor(RewriteDescriptorType::GlobalVariable), Pattern(P), + Transform(T) {} + + bool performOnModule(Module &M) override; + + static bool classof(const RewriteDescriptor *RD) { + return RD->getType() == RewriteDescriptorType::GlobalVariable; + } +}; + +/// ExplicitRewriteNamedAliasDescriptor - represents a rewrite for an explicitly +/// named global alias. Both the source and target name are explicitly spelt +/// out. +class ExplicitRewriteNamedAliasDescriptor : public RewriteDescriptor { +public: + const std::string Source; + const std::string Target; + + ExplicitRewriteNamedAliasDescriptor(StringRef S, StringRef T) + : RewriteDescriptor(RewriteDescriptorType::NamedAlias), Source(S), + Target(T) {} + + bool performOnModule(Module &M) override; + + static bool classof(const RewriteDescriptor *RD) { + return RD->getType() == RewriteDescriptorType::NamedAlias; + } +}; + +/// PatternRewriteNamedAliasDescriptor - represents a rewrite for global +/// aliases which match a given pattern. The provided transformation will be +/// applied to each of the matching names. +class PatternRewriteNamedAliasDescriptor : public RewriteDescriptor { +public: + const std::string Pattern; + const std::string Transform; + + PatternRewriteNamedAliasDescriptor(StringRef P, StringRef T) + : RewriteDescriptor(RewriteDescriptorType::NamedAlias), Pattern(P), + Transform(T) {} + + bool performOnModule(Module &M) override; + + static bool classof(const RewriteDescriptor *RD) { + return RD->getType() == RewriteDescriptorType::NamedAlias; + } +}; + +typedef iplist RewriteDescriptorList; + +class RewriteMapParser { +public: + RewriteMapParser() {} + ~RewriteMapParser() {} + + bool parse(const std::string &MapFile, RewriteDescriptorList *Descriptors); + +private: + bool parse(std::unique_ptr &MapFile, RewriteDescriptorList *DL); + bool parseEntry(yaml::Stream &Stream, yaml::KeyValueNode &Entry, + RewriteDescriptorList *DL); + bool parseRewriteFunctionDescriptor(yaml::Stream &Stream, + yaml::ScalarNode *Key, + yaml::MappingNode *Value, + RewriteDescriptorList *DL); + bool parseRewriteGlobalVariableDescriptor(yaml::Stream &Stream, + yaml::ScalarNode *Key, + yaml::MappingNode *Value, + RewriteDescriptorList *DL); + bool parseRewriteGlobalAliasDescriptor(yaml::Stream &YS, yaml::ScalarNode *K, + yaml::MappingNode *V, + RewriteDescriptorList *DL); +}; +} + +template <> +struct ilist_traits + : public ilist_default_traits { + mutable ilist_half_node Sentinel; + +public: + // createSentinel is used to get a reference to a node marking the end of + // the list. Because the sentinel is relative to this instance, use a + // non-static method. + SymbolRewriter::RewriteDescriptor *createSentinel() const { + // since i[p] lists always publicly derive from the corresponding + // traits, placing a data member in this class will augment the + // i[p]list. Since the NodeTy is expected to publicly derive from + // ilist_node, there is a legal viable downcast from it to + // NodeTy. We use this trick to superpose i[p]list with a "ghostly" + // NodeTy, which becomes the sentinel. Dereferencing the sentinel is + // forbidden (save the ilist_node) so no one will ever notice + // the superposition. + return static_cast(&Sentinel); + } + void destroySentinel(SymbolRewriter::RewriteDescriptor *) {} + + SymbolRewriter::RewriteDescriptor *provideInitialHead() const { + return createSentinel(); + } + + SymbolRewriter::RewriteDescriptor * + ensureHead(SymbolRewriter::RewriteDescriptor *&) const { + return createSentinel(); + } + + static void noteHead(SymbolRewriter::RewriteDescriptor *, + SymbolRewriter::RewriteDescriptor *) {} +}; +} + +#endif Index: lib/CodeGen/Passes.cpp =================================================================== --- lib/CodeGen/Passes.cpp +++ lib/CodeGen/Passes.cpp @@ -445,6 +445,7 @@ void TargetPassConfig::addCodeGenPrepare() { if (getOptLevel() != CodeGenOpt::None && !DisableCGP) addPass(createCodeGenPreparePass(TM)); + addPass(createRewriteSymbolsPass()); } /// Add common passes that perform LLVM IR to IR transforms in preparation for Index: lib/Transforms/Utils/CMakeLists.txt =================================================================== --- lib/Transforms/Utils/CMakeLists.txt +++ lib/Transforms/Utils/CMakeLists.txt @@ -36,6 +36,7 @@ UnifyFunctionExitNodes.cpp Utils.cpp ValueMapper.cpp + SymbolRewriter.cpp ) add_dependencies(LLVMTransformUtils intrinsics_gen) Index: lib/Transforms/Utils/SymbolRewriter.cpp =================================================================== --- /dev/null +++ lib/Transforms/Utils/SymbolRewriter.cpp @@ -0,0 +1,547 @@ +//===- SymbolRewriter.cpp - Symbol Rewriter ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// SymbolRewriter is a LLVM pass which can rewrite symbols transparently within +// existing code. It is implemented as a compiler pass and is configured via a +// YAML configuration file. +// +// The YAML configuration file format is as follows: +// +// RewriteMapFile := RewriteDescriptors +// RewriteDescriptors := RewriteDescriptor | RewriteDescriptors +// RewriteDescriptor := RewriteDescriptorType ':' '{' RewriteDescriptorFields '}' +// RewriteDescriptorFields := RewriteDescriptorField | RewriteDescriptorFields +// RewriteDescriptorField := FieldIdentifier ':' FieldValue ',' +// RewriteDescriptorType := Identifier +// FieldIdentifier := Identifier +// FieldValue := Identifier +// Identifier := [0-9a-zA-Z]+ +// +// Currently, the following descriptor types are supported: +// +// - function: (function rewriting) +// + Source (original name of the function) +// + Target (explicit transformation) +// + Transform (pattern transformation) +// + Naked (boolean, whether the function is undecorated) +// - global variable: (external linkage global variable rewriting) +// + Source (original name of externally visible variable) +// + Target (explicit transformation) +// + Transform (pattern transformation) +// - global alias: (global alias rewriting) +// + Source (original name of the aliased name) +// + Target (explicit transformation) +// + Transform (pattern transformation) +// +// Note that source and exactly one of [Target, Transform] must be provided +// +// New rewrite descriptors can be created. Addding a new rewrite descriptor +// involves: +// +// a) extended the rewrite descriptor kind enumeration +// (::RewriteDescriptor::RewriteDescriptorType) +// b) implementing the new descriptor +// (c.f. ::ExplicitRewriteFunctionDescriptor) +// c) extending the rewrite map parser +// (::RewriteMapParser::parseEntry) +// +// Specify to rewrite the symbols using the `-rewrite-symbols` option, and +// specify the map file to use for the rewriting via the `-rewrite-map-file` +// option. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "symbol-rewriter" +#include "llvm/CodeGen/Passes.h" +#include "llvm/IR/Module.h" +#include "llvm/Pass.h" +#include "llvm/PassManager.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Regex.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/YAMLParser.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/IPO/PassManagerBuilder.h" +#include "llvm/Transforms/Utils/SymbolRewriter.h" + +using namespace llvm; + +static cl::list RewriteMapFiles("rewrite-map-file", + cl::desc("Symbol Rewrite Map"), + cl::value_desc("filename")); + +namespace llvm { +namespace SymbolRewriter { +bool ExplicitRewriteFunctionDescriptor::performOnModule(Module &M) { + Function *F; + bool Changed; + + Changed = false; + if ((F = M.getFunction(Source))) { + if (Value *V = M.getFunction(Target)) + F->setValueName(V->getValueName()); + else + F->setName(Target); + Changed = true; + } + + return Changed; +} + +bool PatternRewriteFunctionDescriptor::performOnModule(Module &M) { + bool Changed; + + Changed = false; + for (auto &Function : M) { + std::string Error; + std::string Name; + + Name = Regex(Pattern).sub(Transform, Function.getName(), &Error); + if (Function.getName() == Name) + continue; + + if (!Error.empty()) + report_fatal_error("unable to transform " + Function.getName() + " in " + + M.getModuleIdentifier() + ": " + Error); + + if (Value *V = M.getFunction(Name)) + Function.setValueName(V->getValueName()); + else + Function.setName(Name); + + Changed = true; + } + + return Changed; +} + +bool ExplicitRewriteGlobalVariableDescriptor::performOnModule(Module &M) { + GlobalVariable *GV; + bool Changed; + + Changed = false; + if ((GV = M.getGlobalVariable(Source))) { + if (Value *V = M.getGlobalVariable(Target)) + GV->setValueName(V->getValueName()); + else + GV->setName(Target); + Changed = true; + } + + return Changed; +} + +bool PatternRewriteGlobalVariableDescriptor::performOnModule(Module &M) { + bool Changed; + + Changed = false; + for (auto &Global : M.globals()) { + std::string Error; + std::string Name; + + Name = Regex(Pattern).sub(Transform, Global.getName(), &Error); + if (Global.getName() == Name) + continue; + + if (!Error.empty()) + report_fatal_error("unable to transform " + Global.getName() + " in " + + M.getModuleIdentifier() + ": " + Error); + + if (Value *V = M.getGlobalVariable(Name)) + Global.setValueName(V->getValueName()); + else + Global.setName(Name); + + Changed = true; + } + + return Changed; +} + +bool ExplicitRewriteNamedAliasDescriptor::performOnModule(Module &M) { + GlobalAlias *GA; + bool Changed; + + Changed = false; + if ((GA = M.getNamedAlias(Source))) { + if (Value *V = M.getNamedAlias(Target)) + GA->setValueName(V->getValueName()); + else + GA->setName(Target); + Changed = true; + } + + return Changed; +} + +bool PatternRewriteNamedAliasDescriptor::performOnModule(Module &M) { + bool Changed; + + Changed = false; + for (auto &Alias : M.aliases()) { + std::string Error; + std::string Name; + + Name = Regex(Pattern).sub(Transform, Alias.getName(), &Error); + if (Alias.getName() == Name) + continue; + + if (!Error.empty()) + report_fatal_error("unable to transform " + Alias.getName() + " in " + + M.getModuleIdentifier() + ": " + Error); + + if (Value *V = M.getNamedAlias(Name)) + Alias.setValueName(V->getValueName()); + else + Alias.setName(Name); + + Changed = true; + } + + return Changed; +} + +bool RewriteMapParser::parse(const std::string &MapFile, + RewriteDescriptorList *DL) { + ErrorOr> Mapping = + MemoryBuffer::getFile(MapFile); + + if (!Mapping) + report_fatal_error("unable to read rewrite map '" + MapFile + "': " + + Mapping.getError().message()); + + if (!parse(*Mapping, DL)) + report_fatal_error("unable to parse rewrite map '" + MapFile + "'"); + + return true; +} + +bool RewriteMapParser::parse(std::unique_ptr &MapFile, + RewriteDescriptorList *DL) { + SourceMgr SM; + yaml::Stream YS(MapFile->getBuffer(), SM); + + for (auto &Document : YS) { + yaml::MappingNode *DescriptorList; + + // ignore empty documents + if (isa(Document.getRoot())) + continue; + + DescriptorList = dyn_cast(Document.getRoot()); + if (!DescriptorList) { + YS.printError(Document.getRoot(), "DescriptorList node must be a map"); + return false; + } + + for (auto &Descriptor : *DescriptorList) + if (!parseEntry(YS, Descriptor, DL)) + return false; + } + + return true; +} + +bool RewriteMapParser::parseEntry(yaml::Stream &YS, yaml::KeyValueNode &Entry, + RewriteDescriptorList *DL) { + const std::string kRewriteTypeFunction = "function"; + const std::string kRewriteTypeGlobalVariable = "global variable"; + const std::string kRewriteTypeGlobalAlias = "global alias"; + + yaml::ScalarNode *Key; + yaml::MappingNode *Value; + SmallString<32> KeyStorage; + StringRef RewriteType; + + Key = dyn_cast(Entry.getKey()); + if (!Key) { + YS.printError(Entry.getKey(), "rewrite type must be a scalar"); + return false; + } + + Value = dyn_cast(Entry.getValue()); + if (!Value) { + YS.printError(Entry.getValue(), "rewrite descriptor must be a map"); + return false; + } + + RewriteType = Key->getValue(KeyStorage); + if (RewriteType == kRewriteTypeFunction) + return parseRewriteFunctionDescriptor(YS, Key, Value, DL); + else if (RewriteType == kRewriteTypeGlobalVariable) + return parseRewriteGlobalVariableDescriptor(YS, Key, Value, DL); + else if (RewriteType == kRewriteTypeGlobalAlias) + return parseRewriteGlobalAliasDescriptor(YS, Key, Value, DL); + + YS.printError(Entry.getKey(), "unknown rewrite type"); + return false; +} + +bool RewriteMapParser:: +parseRewriteFunctionDescriptor(yaml::Stream &YS, yaml::ScalarNode *K, + yaml::MappingNode *Descriptor, + RewriteDescriptorList *DL) { + const std::string kDescriptorFieldSource = "source"; + const std::string kDescriptorFieldTarget = "target"; + const std::string kDescriptorFieldTransform = "transform"; + const std::string kDescriptorFieldNaked = "naked"; + + bool Naked = false; + std::string Source; + std::string Target; + std::string Transform; + + for (auto &Field : *Descriptor) { + yaml::ScalarNode *Key; + yaml::ScalarNode *Value; + SmallString<32> KeyStorage; + SmallString<32> ValueStorage; + StringRef KeyValue; + + Key = dyn_cast(Field.getKey()); + if (!Key) { + YS.printError(Field.getKey(), "descriptor key must be a scalar"); + return false; + } + + Value = dyn_cast(Field.getValue()); + if (!Value) { + YS.printError(Field.getValue(), "descriptor value must be a scalar"); + return false; + } + + KeyValue = Key->getValue(KeyStorage); + if (KeyValue == kDescriptorFieldSource) { + std::string Error; + + Source = Value->getValue(ValueStorage); + if (!Regex(Source).isValid(Error)) { + YS.printError(Field.getKey(), "invalid regex: " + Error); + return false; + } + } else if (KeyValue == kDescriptorFieldTarget) { + Target = Value->getValue(ValueStorage); + } else if (KeyValue == kDescriptorFieldTransform) { + Transform = Value->getValue(ValueStorage); + } else if (KeyValue == kDescriptorFieldNaked) { + std::string Undecorated; + + Undecorated = Value->getValue(ValueStorage); + Naked = StringRef(Undecorated).lower() == "true" || Undecorated == "1"; + } else { + YS.printError(Field.getKey(), "unknown key for function"); + return false; + } + } + + if (Transform.empty() == Target.empty()) { + YS.printError(Descriptor, + "exactly one of transform or target must be specified"); + return false; + } + + // TODO see if there is a more elegant solution to selecting the rewrite + // descriptor type + if (!Target.empty()) + DL->push_back(new ExplicitRewriteFunctionDescriptor(Source, Target, Naked)); + else + DL->push_back(new PatternRewriteFunctionDescriptor(Source, Transform)); + + return true; +} + +bool RewriteMapParser:: +parseRewriteGlobalVariableDescriptor(yaml::Stream &YS, yaml::ScalarNode *K, + yaml::MappingNode *Descriptor, + RewriteDescriptorList *DL) { + const std::string kDescriptorFieldSource = "source"; + const std::string kDescriptorFieldTarget = "target"; + const std::string kDescriptorFieldTransform = "transform"; + + std::string Source; + std::string Target; + std::string Transform; + + for (auto &Field : *Descriptor) { + yaml::ScalarNode *Key; + yaml::ScalarNode *Value; + SmallString<32> KeyStorage; + SmallString<32> ValueStorage; + StringRef KeyValue; + + Key = dyn_cast(Field.getKey()); + if (!Key) { + YS.printError(Field.getKey(), "descriptor Key must be a scalar"); + return false; + } + + Value = dyn_cast(Field.getValue()); + if (!Value) { + YS.printError(Field.getValue(), "descriptor value must be a scalar"); + return false; + } + + KeyValue = Key->getValue(KeyStorage); + if (KeyValue == kDescriptorFieldSource) { + std::string Error; + + Source = Value->getValue(ValueStorage); + if (!Regex(Source).isValid(Error)) { + YS.printError(Field.getKey(), "invalid regex: " + Error); + return false; + } + } else if (KeyValue == kDescriptorFieldTarget) { + Target = Value->getValue(ValueStorage); + } else if (KeyValue == kDescriptorFieldTransform) { + Transform = Value->getValue(ValueStorage); + } else { + YS.printError(Field.getKey(), "unknown Key for Global Variable"); + return false; + } + } + + if (Transform.empty() == Target.empty()) { + YS.printError(Descriptor, + "exactly one of transform or target must be specified"); + return false; + } + + if (!Target.empty()) + DL->push_back(new ExplicitRewriteGlobalVariableDescriptor(Source, Target)); + else + DL->push_back( + new PatternRewriteGlobalVariableDescriptor(Source, Transform)); + + return true; +} + +bool RewriteMapParser:: +parseRewriteGlobalAliasDescriptor(yaml::Stream &YS, yaml::ScalarNode *K, + yaml::MappingNode *Descriptor, + RewriteDescriptorList *DL) { + const std::string kDescriptorFieldSource = "source"; + const std::string kDescriptorFieldTarget = "target"; + const std::string kDescriptorFieldTransform = "transform"; + + std::string Source; + std::string Target; + std::string Transform; + + for (auto &Field : *Descriptor) { + yaml::ScalarNode *Key; + yaml::ScalarNode *Value; + SmallString<32> KeyStorage; + SmallString<32> ValueStorage; + StringRef KeyValue; + + Key = dyn_cast(Field.getKey()); + if (!Key) { + YS.printError(Field.getKey(), "descriptor key must be a scalar"); + return false; + } + + Value = dyn_cast(Field.getValue()); + if (!Value) { + YS.printError(Field.getValue(), "descriptor value must be a scalar"); + return false; + } + + KeyValue = Key->getValue(KeyStorage); + if (KeyValue == kDescriptorFieldSource) { + std::string Error; + + Source = Value->getValue(ValueStorage); + if (!Regex(Source).isValid(Error)) { + YS.printError(Field.getKey(), "invalid regex: " + Error); + return false; + } + } else if (KeyValue == kDescriptorFieldTarget) { + Target = Value->getValue(ValueStorage); + } else if (KeyValue == kDescriptorFieldTransform) { + Transform = Value->getValue(ValueStorage); + } else { + YS.printError(Field.getKey(), "unknown key for Global Alias"); + return false; + } + } + + if (Transform.empty() == Target.empty()) { + YS.printError(Descriptor, + "exactly one of transform or target must be specified"); + return false; + } + + if (!Target.empty()) + DL->push_back(new ExplicitRewriteNamedAliasDescriptor(Source, Target)); + else + DL->push_back(new PatternRewriteNamedAliasDescriptor(Source, Transform)); + + return true; +} +} +} + +namespace { +class RewriteSymbols : public ModulePass { +public: + static char ID; // Pass identification, replacement for typeid + + RewriteSymbols(); + RewriteSymbols(SymbolRewriter::RewriteDescriptorList &DL); + + virtual bool runOnModule(Module &M) override; + +private: + void loadAndParseMapFiles(); + + SymbolRewriter::RewriteDescriptorList Descriptors; +}; + +char RewriteSymbols::ID = 0; + +RewriteSymbols::RewriteSymbols() : ModulePass(ID) { + initializeRewriteSymbolsPass(*PassRegistry::getPassRegistry()); + loadAndParseMapFiles(); +} + +RewriteSymbols::RewriteSymbols(SymbolRewriter::RewriteDescriptorList &DL) + : ModulePass(ID) { + std::swap(Descriptors, DL); +} + +bool RewriteSymbols::runOnModule(Module &M) { + bool Changed; + + Changed = false; + for (auto &Descriptor : Descriptors) + Changed |= Descriptor.performOnModule(M); + + return Changed; +} + +void RewriteSymbols::loadAndParseMapFiles() { + const std::vector MapFiles(RewriteMapFiles); + SymbolRewriter::RewriteMapParser parser; + + for (const auto &MapFile : MapFiles) + parser.parse(MapFile, &Descriptors); +} +} + +INITIALIZE_PASS(RewriteSymbols, "rewrite-symbols", "Rewrite Symbols", false, + false); + +ModulePass *llvm::createRewriteSymbolsPass() { return new RewriteSymbols(); } + +ModulePass * +llvm::createRewriteSymbolsPass(SymbolRewriter::RewriteDescriptorList &DL) { + return new RewriteSymbols(DL); +} Index: test/SymbolRewriter/rewrite.ll =================================================================== --- /dev/null +++ test/SymbolRewriter/rewrite.ll @@ -0,0 +1,59 @@ +; RUN: opt -mtriple i686-win32 -rewrite-symbols -rewrite-map-file %p/rewrite.map \ +; RUN: %s -o - | llvm-dis | FileCheck %s + +declare void @source_function() +@source_variable = external global i32 +declare void @source_function_pattern_function() +declare void @source_function_pattern_multiple_function_matches() +@source_variable_pattern_variable = external global i32 +@source_variable_pattern_multiple_variable_matches = external global i32 +declare void @"\01naked_source_function"() +declare void @"\01__imp_missing_global_leader_prefix"() + +declare i32 @first_callee() +declare i32 @second_callee() +define i32 @caller() { + %rhs = call i32 @first_callee() + %lhs = call i32 @second_callee() + %res = add i32 %rhs, %lhs + ret i32 %res +} + +%struct.S = type { i8 } +@_ZN1SC1Ev = alias void (%struct.S*)* @_ZN1SC2Ev +define void @_ZN1SC2Ev(%struct.S* %this) unnamed_addr align 2 { +entry: + %this.addr = alloca %struct.S*, align 4 + store %struct.S* %this, %struct.S** %this.addr, align 4 + ret void +} + +; CHECK: @target_variable = external global i32 +; CHECK-NOT: @source_variable = external global i32 +; CHECK: @target_pattern_variable = external global i32 +; CHECK-NOT: @source_pattern_variable = external global i32 +; CHECK: @target_pattern_multiple_variable_matches = external global i32 +; CHECK-NOT: @source_pattern_multiple_variable_matches = external global i32 +; CHECK: declare void @target_function() +; CHECK-NOT: declare void @source_function() +; CHECK: declare void @target_pattern_function() +; CHECK-NOT: declare void @source_function_pattern_function() +; CHECK: declare void @target_pattern_multiple_function_matches() +; CHECK-NOT: declare void @source_function_pattern_multiple_function_matches() +; CHECK: declare void @naked_target_function() +; CHECK-NOT: declare void @"\01naked_source_function"() +; CHECK-NOT: declare void @"\01__imp__imported_function"() +; CHECK: declare void @"\01__imp_missing_global_leader_prefix"() +; CHECK-NOT: declare void @"\01__imp_DO_NOT_REWRITE"() + +; CHECK: declare i32 @renamed_callee() +; CHECK-NOT: declare i32 @first_callee() +; CHECK: declare i32 @second_callee() +; CHECK: define i32 @caller() { +; CHECK: %rhs = call i32 @renamed_callee() +; CHECK-NOT: %rhs = call i32 @first_callee() +; CHECK: %lhs = call i32 @second_callee() +; CHECK: %res = add i32 %rhs, %lhs +; CHECK: ret i32 %res +; CHECK: } + Index: test/SymbolRewriter/rewrite.map =================================================================== --- /dev/null +++ test/SymbolRewriter/rewrite.map @@ -0,0 +1,46 @@ +function: { + source: source_function, + target: target_function, +} + +global variable: { + source: source_variable, + target: target_variable, +} + +function: { + source: source_function_(.*), + transform: target_\1, +} + +global variable: { + source: source_variable_(.*), + transform: target_\1, +} + +function: { + source: naked_source_function, + target: naked_target_function, + naked: true, +} + +function: { + source: imported_function, + target: exported_function, +} + +function: { + source: missing_global_leader_prefix, + target: DO_NOT_REWRITE, +} + +function: { + source: first_callee, + target: renamed_callee, +} + +global alias: { + source: _ZN1SC1Ev, + target: _ZN1SD1Ev, +} + Index: tools/opt/opt.cpp =================================================================== --- tools/opt/opt.cpp +++ tools/opt/opt.cpp @@ -346,6 +346,7 @@ // supported. initializeCodeGenPreparePass(Registry); initializeAtomicExpandPass(Registry); + initializeRewriteSymbolsPass(Registry); #ifdef LINK_POLLY_INTO_TOOLS polly::initializePollyPasses(Registry);