Index: include/llvm/InitializePasses.h =================================================================== --- include/llvm/InitializePasses.h +++ include/llvm/InitializePasses.h @@ -269,6 +269,7 @@ void initializeBBVectorizePass(PassRegistry&); void initializeMachineFunctionPrinterPassPass(PassRegistry&); void initializeStackMapLivenessPass(PassRegistry&); +void initializeRewriteSymbolsPass(PassRegistry &); } #endif Index: lib/CodeGen/CodeGenPrepare.cpp =================================================================== --- lib/CodeGen/CodeGenPrepare.cpp +++ lib/CodeGen/CodeGenPrepare.cpp @@ -151,6 +151,7 @@ void llvm::initializeCodeGenPreparePass(PassRegistry &Registry) { CALL_ONCE_INITIALIZATION(initializeCodeGenPreparePassOnce) + initializeRewriteSymbolsPass(Registry); } FunctionPass *llvm::createCodeGenPreparePass(const TargetMachine *TM) { Index: lib/CodeGen/LLVMBuild.txt =================================================================== --- lib/CodeGen/LLVMBuild.txt +++ lib/CodeGen/LLVMBuild.txt @@ -22,4 +22,4 @@ type = Library name = CodeGen parent = Libraries -required_libraries = Analysis Core MC Scalar Support Target TransformUtils +required_libraries = Analysis Core MC Scalar Support SymbolRewriter Target TransformUtils Index: lib/Transforms/CMakeLists.txt =================================================================== --- lib/Transforms/CMakeLists.txt +++ lib/Transforms/CMakeLists.txt @@ -2,6 +2,7 @@ add_subdirectory(Instrumentation) add_subdirectory(InstCombine) add_subdirectory(Scalar) +add_subdirectory(SymbolRewriter) add_subdirectory(IPO) add_subdirectory(Vectorize) add_subdirectory(Hello) Index: lib/Transforms/LLVMBuild.txt =================================================================== --- lib/Transforms/LLVMBuild.txt +++ lib/Transforms/LLVMBuild.txt @@ -16,7 +16,7 @@ ;===------------------------------------------------------------------------===; [common] -subdirectories = IPO InstCombine Instrumentation Scalar Utils Vectorize ObjCARC +subdirectories = IPO InstCombine Instrumentation Scalar SymbolRewriter Utils Vectorize ObjCARC [component_0] type = Group Index: lib/Transforms/Makefile =================================================================== --- lib/Transforms/Makefile +++ lib/Transforms/Makefile @@ -8,7 +8,8 @@ ##===----------------------------------------------------------------------===## LEVEL = ../.. -PARALLEL_DIRS = Utils Instrumentation Scalar InstCombine IPO Vectorize Hello ObjCARC +PARALLEL_DIRS = Utils Instrumentation Scalar InstCombine IPO Vectorize Hello \ + ObjCARC SymbolRewriter include $(LEVEL)/Makefile.config Index: lib/Transforms/SymbolRewriter/CMakeLists.txt =================================================================== --- /dev/null +++ lib/Transforms/SymbolRewriter/CMakeLists.txt @@ -0,0 +1,4 @@ +add_llvm_library(LLVMSymbolRewriter + SymbolRewriter.cpp) +add_dependencies(LLVMSymbolRewriter intrinsics_gen) + Index: lib/Transforms/SymbolRewriter/LLVMBuild.txt =================================================================== --- lib/Transforms/SymbolRewriter/LLVMBuild.txt +++ lib/Transforms/SymbolRewriter/LLVMBuild.txt @@ -15,10 +15,9 @@ ; ;===------------------------------------------------------------------------===; -[common] -subdirectories = IPO InstCombine Instrumentation Scalar Utils Vectorize ObjCARC - [component_0] -type = Group -name = Transforms -parent = Libraries +type = Library +name = SymbolRewriter +parent = Transforms +required_libraries = Support + Index: lib/Transforms/SymbolRewriter/Makefile =================================================================== --- /dev/null +++ lib/Transforms/SymbolRewriter/Makefile @@ -0,0 +1,16 @@ +##===- lib/Transforms/SymbolRewriter/Makefile --------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../.. + +BUILD_ARCHIVE = 1 +LIBRARYNAME = LLVMSymbolRewriter + +include $(LEVEL)/Makefile.common + Index: lib/Transforms/SymbolRewriter/SymbolRewriter.cpp =================================================================== --- /dev/null +++ lib/Transforms/SymbolRewriter/SymbolRewriter.cpp @@ -0,0 +1,776 @@ +//===- 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 rewritting) +// + 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/ADT/ilist.h" +#include "llvm/ADT/ilist_node.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/Triple.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/Support/system_error.h" +#include "llvm/Transforms/IPO/PassManagerBuilder.h" + +using namespace llvm; + +static cl::list RewriteMapFiles("rewrite-map-file", + cl::desc("Symbol Rewrite Map"), + cl::value_desc("filename")); + +namespace { +bool IsOSWindows(const Module &M) { + const Triple T(M.getTargetTriple()); + return T.isOSWindows(); +} + +std::string Import(const Module &M, StringRef Name) { + const std::string ImpPrefix = "\01__imp_"; + const Triple T(M.getTargetTriple()); + assert(T.isOSWindows()); + if (T.getArch() == llvm::Triple::x86) + return (ImpPrefix + "_" + Name).str(); + return (ImpPrefix + Name).str(); +} + +class RewriteDescriptor : public ilist_node { + RewriteDescriptor(const RewriteDescriptor &) LLVM_DELETED_FUNCTION; + + const RewriteDescriptor & + operator=(const RewriteDescriptor &) LLVM_DELETED_FUNCTION; + +public: + enum RewriteDescriptorType { + RDT_Invalid, + RDT_Function, + RDT_GlobalVariable, + RDT_NamedAlias + }; + + virtual ~RewriteDescriptor() {} + + RewriteDescriptorType getType() const { return Type; } + + virtual bool performOnModule(Module &M) = 0; + +protected: + explicit RewriteDescriptor(RewriteDescriptorType T) : Type(T) {} + +private: + const RewriteDescriptorType Type; +}; + +class ExplicitRewriteFunctionDescriptor : public RewriteDescriptor { +public: + const std::string Source; + const std::string Target; + + ExplicitRewriteFunctionDescriptor(const StringRef S, const StringRef T, + const bool Naked) + : RewriteDescriptor(RDT_Function), + Source(Naked ? StringRef("\01" + S.str()) : S), Target(T) {} + + bool performOnModule(Module &M) override; + + static bool classof(const RewriteDescriptor *RD) { + return RD->getType() == RDT_Function; + } +}; + +class PatternRewriteFunctionDescriptor : public RewriteDescriptor { +public: + const std::string Pattern; + const std::string Transform; + + PatternRewriteFunctionDescriptor(const StringRef P, const StringRef T) + : RewriteDescriptor(RDT_Function), Pattern(P), Transform(T) {} + + bool performOnModule(Module &M) override; + + static bool classof(const RewriteDescriptor *RD) { + return RD->getType() == RDT_Function; + } +}; + +class ExplicitRewriteGlobalVariableDescriptor : public RewriteDescriptor { +public: + const std::string Source; + const std::string Target; + + ExplicitRewriteGlobalVariableDescriptor(const StringRef S, const StringRef T) + : RewriteDescriptor(RDT_GlobalVariable), Source(S), Target(T) {} + + bool performOnModule(Module &M) override; + + static bool classof(const RewriteDescriptor *RD) { + return RD->getType() == RDT_GlobalVariable; + } +}; + +class PatternRewriteGlobalVariableDescriptor : public RewriteDescriptor { +public: + const std::string Pattern; + const std::string Transform; + + PatternRewriteGlobalVariableDescriptor(const StringRef P, const StringRef T) + : RewriteDescriptor(RDT_GlobalVariable), Pattern(P), Transform(T) {} + + bool performOnModule(Module &M) override; + + static bool classof(const RewriteDescriptor *RD) { + return RD->getType() == RDT_GlobalVariable; + } +}; + +class ExplicitRewriteNamedAliasDescriptor : public RewriteDescriptor { +public: + const std::string Source; + const std::string Target; + + ExplicitRewriteNamedAliasDescriptor(const StringRef S, const StringRef T) + : RewriteDescriptor(RDT_NamedAlias), Source(S), Target(T) {} + + bool performOnModule(Module &M) override; + + static bool classof(const RewriteDescriptor *RD) { + return RD->getType() == RDT_NamedAlias; + } +}; + +class PatternRewriteNamedAliasDescriptor : public RewriteDescriptor { +public: + const std::string Pattern; + const std::string Transform; + + PatternRewriteNamedAliasDescriptor(const StringRef P, const StringRef T) + : RewriteDescriptor(RDT_NamedAlias), Pattern(P), Transform(T) {} + + bool performOnModule(Module &M) override; + + static bool classof(const RewriteDescriptor *RD) { + return RD->getType() == RDT_NamedAlias; + } +}; + +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; + } + + if (IsOSWindows(M)) { + if ((F = M.getFunction(Import(M, Source)))) { + if (Value *V = M.getFunction(Import(M, Target))) + F->setValueName(V->getValueName()); + else + F->setName(Import(M, Target)); + Changed = true; + } + + if (GlobalVariable *GV = M.getGlobalVariable(Import(M, Source))) { + if (Value *V = M.getFunction(Import(M, Target))) + GV->setValueName(V->getValueName()); + else + GV->setName(Import(M, Target)); + Changed = true; + } + } + + return Changed; +} + +bool PatternRewriteFunctionDescriptor::performOnModule(Module &M) { + bool Changed; + + Changed = false; + for (Module::iterator FI = M.begin(), FE = M.end(); FI != FE; ++FI) { + std::string Error; + std::string Name; + + Name = Regex(Pattern).sub(Transform, FI->getName(), &Error); + if (FI->getName() == Name) + continue; + + if (!Error.empty()) + report_fatal_error("unable to transform " + FI->getName() + " in " + + M.getModuleIdentifier() + ": " + Error); + + if (Value *V = M.getFunction(Name)) + FI->setValueName(V->getValueName()); + else + FI->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; + } + + if (IsOSWindows(M)) { + if ((GV = M.getGlobalVariable(Import(M, Source)))) { + if (Value *V = M.getGlobalVariable(Import(M, Target))) + GV->setValueName(V->getValueName()); + else + GV->setName(Import(M, Target)); + Changed = true; + } + } + + return Changed; +} + +bool PatternRewriteGlobalVariableDescriptor::performOnModule(Module &M) { + bool Changed; + + Changed = false; + for (Module::global_iterator GI = M.global_begin(), GE = M.global_end(); + GI != GE; ++GI) { + std::string Error; + std::string Name; + + Name = Regex(Pattern).sub(Transform, GI->getName(), &Error); + if (GI->getName() == Name) + continue; + + if (!Error.empty()) + report_fatal_error("unable to transform " + GI->getName() + " in " + + M.getModuleIdentifier() + ": " + Error); + + if (Value *V = M.getGlobalVariable(Name)) + GI->setValueName(V->getValueName()); + else + GI->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; + } + + if (IsOSWindows(M)) { + if ((GA = M.getNamedAlias(Import(M, Source)))) { + if (Value *V = M.getNamedAlias(Import(M, Target))) + GA->setValueName(V->getValueName()); + else + GA->setName(Import(M, Target)); + Changed = true; + } + } + + return Changed; +} + +bool PatternRewriteNamedAliasDescriptor::performOnModule(Module &M) { + bool Changed; + + Changed = false; + for (Module::alias_iterator AI = M.alias_begin(), AE = M.alias_end(); + AI != AE; ++AI) { + std::string Error; + std::string Name; + + Name = Regex(Pattern).sub(Transform, AI->getName(), &Error); + if (AI->getName() == Name) + continue; + + if (!Error.empty()) + report_fatal_error("unable to transform " + AI->getName() + " in " + + M.getModuleIdentifier() + ": " + Error); + + if (Value *V = M.getNamedAlias(Name)) + AI->setValueName(V->getValueName()); + else + AI->setName(Name); + + Changed = true; + } + + return Changed; +} +} + +namespace llvm { +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. + 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(RewriteDescriptor *) {} + + RewriteDescriptor *provideInitialHead() const { return createSentinel(); } + RewriteDescriptor *ensureHead(RewriteDescriptor *&) const { + return createSentinel(); + } + + static void noteHead(RewriteDescriptor *, RewriteDescriptor *) {} +}; +} + +namespace { +typedef iplist RewriteDescriptorList; + +class RewriteMapParser { +public: + RewriteMapParser() {} + ~RewriteMapParser() {} + + bool parse(const std::string &MapFile, RewriteDescriptorList *Descriptors); + +private: + bool parse(OwningPtr &MapFile, RewriteDescriptorList *DL); + bool parseEntry(yaml::Stream &Stream, yaml::Node *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); +}; + +bool RewriteMapParser::parse(const std::string &MapFile, + RewriteDescriptorList *DL) { + OwningPtr Mapping; + + if (error_code Result = MemoryBuffer::getFile(MapFile, Mapping)) + report_fatal_error("unable to read rewrite map '" + MapFile + "': " + + Result.message()); + + if (!parse(Mapping, DL)) + report_fatal_error("unable to parse rewrite map '" + MapFile + "'"); + + return true; +} + +bool RewriteMapParser::parse(OwningPtr &MapFile, + RewriteDescriptorList *DL) { + SourceMgr SM; + yaml::Stream YS(MapFile->getBuffer(), SM); + + for (yaml::document_iterator DI = YS.begin(), DE = YS.end(); DI != DE; ++DI) { + yaml::MappingNode *Root; + + // ignore empty documents + if (isa(DI->getRoot())) + continue; + + Root = dyn_cast(DI->getRoot()); + if (!Root) { + YS.printError(DI->getRoot(), "root node must be a map"); + return false; + } + + for (yaml::MappingNode::iterator EI = Root->begin(), EE = Root->end(); + EI != EE; ++EI) + if (!parseEntry(YS, EI, DL)) + return false; + } + + return true; +} + +bool RewriteMapParser::parseEntry(yaml::Stream &YS, yaml::Node *E, + 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; + yaml::KeyValueNode *Entry; + SmallString<32> KeyStorage; + StringRef RewriteType; + + Entry = dyn_cast(E); + if (!Entry) { + YS.printError(E, "entry must be a map"); + return false; + } + + 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 *V, + 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 (yaml::MappingNode::iterator DF = V->begin(), DE = V->end(); DF != DE; + ++DF) { + yaml::ScalarNode *Field; + yaml::ScalarNode *Value; + SmallString<32> FieldStorage; + SmallString<32> ValueStorage; + StringRef FieldValue; + + Field = dyn_cast(DF->getKey()); + if (!Field) { + YS.printError(DF->getKey(), "descriptor field must be a scalar"); + return false; + } + + Value = dyn_cast(DF->getValue()); + if (!Value) { + YS.printError(DF->getValue(), "descriptor value must be a scalar"); + return false; + } + + FieldValue = Field->getValue(FieldStorage); + if (FieldValue == kDescriptorFieldSource) { + std::string Error; + + Source = Value->getValue(ValueStorage); + if (!Regex(Source).isValid(Error)) { + YS.printError(DF->getKey(), "invalid regex: " + Error); + return false; + } + } else if (FieldValue == kDescriptorFieldTarget) { + Target = Value->getValue(ValueStorage); + } else if (FieldValue == kDescriptorFieldTransform) { + + Transform = Value->getValue(ValueStorage); + } else if (FieldValue == kDescriptorFieldNaked) { + std::string Undecorated; + + Undecorated = Value->getValue(ValueStorage); + Naked = StringRef(Undecorated).lower() == "true" || Undecorated == "1"; + } else { + YS.printError(DF->getKey(), "unknown field for function"); + return false; + } + } + + if (!(Transform.empty() ^ Target.empty())) { + YS.printError(V, "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 *V, + 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 (yaml::MappingNode::iterator DF = V->begin(), DE = V->end(); DF != DE; + ++DF) { + yaml::ScalarNode *Field; + yaml::ScalarNode *Value; + SmallString<32> FieldStorage; + SmallString<32> ValueStorage; + StringRef FieldValue; + + Field = dyn_cast(DF->getKey()); + if (!Field) { + YS.printError(DF->getKey(), "descriptor field must be a scalar"); + return false; + } + + Value = dyn_cast(DF->getValue()); + if (!Value) { + YS.printError(DF->getValue(), "descriptor value must be a scalar"); + return false; + } + + FieldValue = Field->getValue(FieldStorage); + if (FieldValue == kDescriptorFieldSource) { + std::string Error; + + Source = Value->getValue(ValueStorage); + if (!Regex(Source).isValid(Error)) { + YS.printError(DF->getKey(), "invalid regex: " + Error); + return false; + } + } else if (FieldValue == kDescriptorFieldTarget) { + Target = Value->getValue(ValueStorage); + } else if (FieldValue == kDescriptorFieldTransform) { + std::string Error; + + Transform = Value->getValue(ValueStorage); + } else { + YS.printError(DF->getKey(), "unknown field for Global Variable"); + return false; + } + } + + if (!(Transform.empty() ^ Target.empty())) { + YS.printError(V, "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 *V, + 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 (yaml::MappingNode::iterator DF = V->begin(), DE = V->end(); DF != DE; + ++DF) { + yaml::ScalarNode *Field; + yaml::ScalarNode *Value; + SmallString<32> FieldStorage; + SmallString<32> ValueStorage; + StringRef FieldValue; + + Field = dyn_cast(DF->getKey()); + if (!Field) { + YS.printError(DF->getKey(), "descriptor field must be a scalar"); + return false; + } + + Value = dyn_cast(DF->getValue()); + if (!Value) { + YS.printError(DF->getValue(), "descriptor value must be a scalar"); + return false; + } + + FieldValue = Field->getValue(FieldStorage); + if (FieldValue == kDescriptorFieldSource) { + std::string Error; + + Source = Value->getValue(ValueStorage); + if (!Regex(Source).isValid(Error)) { + YS.printError(DF->getKey(), "invalid regex: " + Error); + return false; + } + } else if (FieldValue == kDescriptorFieldTarget) { + Target = Value->getValue(ValueStorage); + } else if (FieldValue == kDescriptorFieldTransform) { + Transform = Value->getValue(ValueStorage); + } else { + YS.printError(DF->getKey(), "unknown field for Global Alias"); + return false; + } + } + + if (!(Transform.empty() ^ Target.empty())) { + YS.printError(V, "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(); + + virtual bool runOnModule(Module &M) override; + +private: + void loadAndParseMapFiles(); + + RewriteDescriptorList Descriptors; +}; + +char RewriteSymbols::ID = 0; + +RewriteSymbols::RewriteSymbols() : ModulePass(ID) { loadAndParseMapFiles(); } + +bool RewriteSymbols::runOnModule(Module &M) { + bool Changed; + + Changed = false; + for (RewriteDescriptorList::iterator DI = Descriptors.begin(), + DE = Descriptors.end(); + DI != DE; ++DI) + Changed |= DI->performOnModule(M); + + return Changed; +} + +void RewriteSymbols::loadAndParseMapFiles() { + const std::vector MapFiles(RewriteMapFiles); + RewriteMapParser parser; + + for (std::vector::const_iterator MI = MapFiles.begin(), + ME = MapFiles.end(); + MI != ME; ++MI) + parser.parse(*MI, &Descriptors); +} +} + +INITIALIZE_PASS(RewriteSymbols, "rewrite-symbols", "Rewrite Symbols", + false, false); + Index: test/SymbolRewriter/rewrite.ll =================================================================== --- /dev/null +++ test/SymbolRewriter/rewrite.ll @@ -0,0 +1,61 @@ +; 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__imported_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: declare void @"\01__imp__exported_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, +} +