10b57cec5SDimitry Andric //===- MetaRenamer.cpp - Rename everything with metasyntatic names --------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This pass renames everything with metasyntatic names. The intent is to use
100b57cec5SDimitry Andric // this pass after bugpoint reduction to conceal the nature of the original
110b57cec5SDimitry Andric // program.
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric
15e8d8bef9SDimitry Andric #include "llvm/Transforms/Utils/MetaRenamer.h"
160b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
170b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h"
180eae32dcSDimitry Andric #include "llvm/ADT/SmallVector.h"
190b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
200b57cec5SDimitry Andric #include "llvm/ADT/Twine.h"
210b57cec5SDimitry Andric #include "llvm/Analysis/TargetLibraryInfo.h"
220b57cec5SDimitry Andric #include "llvm/IR/Argument.h"
230b57cec5SDimitry Andric #include "llvm/IR/BasicBlock.h"
240b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h"
250b57cec5SDimitry Andric #include "llvm/IR/Function.h"
260b57cec5SDimitry Andric #include "llvm/IR/GlobalAlias.h"
270b57cec5SDimitry Andric #include "llvm/IR/GlobalVariable.h"
280b57cec5SDimitry Andric #include "llvm/IR/Instruction.h"
2906c3fb27SDimitry Andric #include "llvm/IR/InstIterator.h"
300b57cec5SDimitry Andric #include "llvm/IR/Module.h"
31e8d8bef9SDimitry Andric #include "llvm/IR/PassManager.h"
320b57cec5SDimitry Andric #include "llvm/IR/Type.h"
330b57cec5SDimitry Andric #include "llvm/IR/TypeFinder.h"
340eae32dcSDimitry Andric #include "llvm/Support/CommandLine.h"
350b57cec5SDimitry Andric
360b57cec5SDimitry Andric using namespace llvm;
370b57cec5SDimitry Andric
380eae32dcSDimitry Andric static cl::opt<std::string> RenameExcludeFunctionPrefixes(
390eae32dcSDimitry Andric "rename-exclude-function-prefixes",
400eae32dcSDimitry Andric cl::desc("Prefixes for functions that don't need to be renamed, separated "
410eae32dcSDimitry Andric "by a comma"),
420eae32dcSDimitry Andric cl::Hidden);
430eae32dcSDimitry Andric
440eae32dcSDimitry Andric static cl::opt<std::string> RenameExcludeAliasPrefixes(
450eae32dcSDimitry Andric "rename-exclude-alias-prefixes",
460eae32dcSDimitry Andric cl::desc("Prefixes for aliases that don't need to be renamed, separated "
470eae32dcSDimitry Andric "by a comma"),
480eae32dcSDimitry Andric cl::Hidden);
490eae32dcSDimitry Andric
500eae32dcSDimitry Andric static cl::opt<std::string> RenameExcludeGlobalPrefixes(
510eae32dcSDimitry Andric "rename-exclude-global-prefixes",
520eae32dcSDimitry Andric cl::desc(
530eae32dcSDimitry Andric "Prefixes for global values that don't need to be renamed, separated "
540eae32dcSDimitry Andric "by a comma"),
550eae32dcSDimitry Andric cl::Hidden);
560eae32dcSDimitry Andric
570eae32dcSDimitry Andric static cl::opt<std::string> RenameExcludeStructPrefixes(
580eae32dcSDimitry Andric "rename-exclude-struct-prefixes",
590eae32dcSDimitry Andric cl::desc("Prefixes for structs that don't need to be renamed, separated "
600eae32dcSDimitry Andric "by a comma"),
610eae32dcSDimitry Andric cl::Hidden);
620eae32dcSDimitry Andric
6306c3fb27SDimitry Andric static cl::opt<bool>
6406c3fb27SDimitry Andric RenameOnlyInst("rename-only-inst", cl::init(false),
6506c3fb27SDimitry Andric cl::desc("only rename the instructions in the function"),
6606c3fb27SDimitry Andric cl::Hidden);
6706c3fb27SDimitry Andric
680b57cec5SDimitry Andric static const char *const metaNames[] = {
690b57cec5SDimitry Andric // See http://en.wikipedia.org/wiki/Metasyntactic_variable
700b57cec5SDimitry Andric "foo", "bar", "baz", "quux", "barney", "snork", "zot", "blam", "hoge",
710b57cec5SDimitry Andric "wibble", "wobble", "widget", "wombat", "ham", "eggs", "pluto", "spam"
720b57cec5SDimitry Andric };
730b57cec5SDimitry Andric
740b57cec5SDimitry Andric namespace {
750b57cec5SDimitry Andric // This PRNG is from the ISO C spec. It is intentionally simple and
760b57cec5SDimitry Andric // unsuitable for cryptographic use. We're just looking for enough
770b57cec5SDimitry Andric // variety to surprise and delight users.
780b57cec5SDimitry Andric struct PRNG {
790b57cec5SDimitry Andric unsigned long next;
800b57cec5SDimitry Andric
srand__anonbc5a2a510111::PRNG81e8d8bef9SDimitry Andric void srand(unsigned int seed) { next = seed; }
820b57cec5SDimitry Andric
rand__anonbc5a2a510111::PRNG830b57cec5SDimitry Andric int rand() {
840b57cec5SDimitry Andric next = next * 1103515245 + 12345;
850b57cec5SDimitry Andric return (unsigned int)(next / 65536) % 32768;
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric };
880b57cec5SDimitry Andric
890b57cec5SDimitry Andric struct Renamer {
Renamer__anonbc5a2a510111::Renamer90e8d8bef9SDimitry Andric Renamer(unsigned int seed) { prng.srand(seed); }
910b57cec5SDimitry Andric
newName__anonbc5a2a510111::Renamer920b57cec5SDimitry Andric const char *newName() {
93bdd1243dSDimitry Andric return metaNames[prng.rand() % std::size(metaNames)];
940b57cec5SDimitry Andric }
950b57cec5SDimitry Andric
960b57cec5SDimitry Andric PRNG prng;
970b57cec5SDimitry Andric };
980b57cec5SDimitry Andric
990eae32dcSDimitry Andric static void
parseExcludedPrefixes(StringRef PrefixesStr,SmallVectorImpl<StringRef> & ExcludedPrefixes)1000eae32dcSDimitry Andric parseExcludedPrefixes(StringRef PrefixesStr,
1010eae32dcSDimitry Andric SmallVectorImpl<StringRef> &ExcludedPrefixes) {
1020eae32dcSDimitry Andric for (;;) {
1030eae32dcSDimitry Andric auto PrefixesSplit = PrefixesStr.split(',');
1040eae32dcSDimitry Andric if (PrefixesSplit.first.empty())
1050eae32dcSDimitry Andric break;
1060eae32dcSDimitry Andric ExcludedPrefixes.push_back(PrefixesSplit.first);
1070eae32dcSDimitry Andric PrefixesStr = PrefixesSplit.second;
1080eae32dcSDimitry Andric }
1090eae32dcSDimitry Andric }
1100eae32dcSDimitry Andric
MetaRenameOnlyInstructions(Function & F)11106c3fb27SDimitry Andric void MetaRenameOnlyInstructions(Function &F) {
11206c3fb27SDimitry Andric for (auto &I : instructions(F))
11306c3fb27SDimitry Andric if (!I.getType()->isVoidTy() && I.getName().empty())
11406c3fb27SDimitry Andric I.setName(I.getOpcodeName());
11506c3fb27SDimitry Andric }
11606c3fb27SDimitry Andric
MetaRename(Function & F)117e8d8bef9SDimitry Andric void MetaRename(Function &F) {
118fe6060f1SDimitry Andric for (Argument &Arg : F.args())
119fe6060f1SDimitry Andric if (!Arg.getType()->isVoidTy())
120fe6060f1SDimitry Andric Arg.setName("arg");
1210b57cec5SDimitry Andric
122e8d8bef9SDimitry Andric for (auto &BB : F) {
123e8d8bef9SDimitry Andric BB.setName("bb");
124e8d8bef9SDimitry Andric
125e8d8bef9SDimitry Andric for (auto &I : BB)
126e8d8bef9SDimitry Andric if (!I.getType()->isVoidTy())
12706c3fb27SDimitry Andric I.setName(I.getOpcodeName());
128e8d8bef9SDimitry Andric }
1290b57cec5SDimitry Andric }
1300b57cec5SDimitry Andric
MetaRename(Module & M,function_ref<TargetLibraryInfo & (Function &)> GetTLI)131e8d8bef9SDimitry Andric void MetaRename(Module &M,
132e8d8bef9SDimitry Andric function_ref<TargetLibraryInfo &(Function &)> GetTLI) {
1330b57cec5SDimitry Andric // Seed our PRNG with simple additive sum of ModuleID. We're looking to
1340b57cec5SDimitry Andric // simply avoid always having the same function names, and we need to
1350b57cec5SDimitry Andric // remain deterministic.
1360b57cec5SDimitry Andric unsigned int randSeed = 0;
1370b57cec5SDimitry Andric for (auto C : M.getModuleIdentifier())
1380b57cec5SDimitry Andric randSeed += C;
1390b57cec5SDimitry Andric
1400b57cec5SDimitry Andric Renamer renamer(randSeed);
1410b57cec5SDimitry Andric
1420eae32dcSDimitry Andric SmallVector<StringRef, 8> ExcludedAliasesPrefixes;
1430eae32dcSDimitry Andric SmallVector<StringRef, 8> ExcludedGlobalsPrefixes;
1440eae32dcSDimitry Andric SmallVector<StringRef, 8> ExcludedStructsPrefixes;
1450eae32dcSDimitry Andric SmallVector<StringRef, 8> ExcludedFuncPrefixes;
1460eae32dcSDimitry Andric parseExcludedPrefixes(RenameExcludeAliasPrefixes, ExcludedAliasesPrefixes);
1470eae32dcSDimitry Andric parseExcludedPrefixes(RenameExcludeGlobalPrefixes, ExcludedGlobalsPrefixes);
1480eae32dcSDimitry Andric parseExcludedPrefixes(RenameExcludeStructPrefixes, ExcludedStructsPrefixes);
1490eae32dcSDimitry Andric parseExcludedPrefixes(RenameExcludeFunctionPrefixes, ExcludedFuncPrefixes);
1500eae32dcSDimitry Andric
1510eae32dcSDimitry Andric auto IsNameExcluded = [](StringRef &Name,
1520eae32dcSDimitry Andric SmallVectorImpl<StringRef> &ExcludedPrefixes) {
1530eae32dcSDimitry Andric return any_of(ExcludedPrefixes,
154*5f757f3fSDimitry Andric [&Name](auto &Prefix) { return Name.starts_with(Prefix); });
1550eae32dcSDimitry Andric };
1560eae32dcSDimitry Andric
15706c3fb27SDimitry Andric // Leave library functions alone because their presence or absence could
15806c3fb27SDimitry Andric // affect the behavior of other passes.
15906c3fb27SDimitry Andric auto ExcludeLibFuncs = [&](Function &F) {
16006c3fb27SDimitry Andric LibFunc Tmp;
16106c3fb27SDimitry Andric StringRef Name = F.getName();
162*5f757f3fSDimitry Andric return Name.starts_with("llvm.") || (!Name.empty() && Name[0] == 1) ||
16306c3fb27SDimitry Andric GetTLI(F).getLibFunc(F, Tmp) ||
16406c3fb27SDimitry Andric IsNameExcluded(Name, ExcludedFuncPrefixes);
16506c3fb27SDimitry Andric };
16606c3fb27SDimitry Andric
16706c3fb27SDimitry Andric if (RenameOnlyInst) {
16806c3fb27SDimitry Andric // Rename all functions
16906c3fb27SDimitry Andric for (auto &F : M) {
17006c3fb27SDimitry Andric if (ExcludeLibFuncs(F))
17106c3fb27SDimitry Andric continue;
17206c3fb27SDimitry Andric MetaRenameOnlyInstructions(F);
17306c3fb27SDimitry Andric }
17406c3fb27SDimitry Andric return;
17506c3fb27SDimitry Andric }
17606c3fb27SDimitry Andric
1770b57cec5SDimitry Andric // Rename all aliases
1785e801ac6SDimitry Andric for (GlobalAlias &GA : M.aliases()) {
1795e801ac6SDimitry Andric StringRef Name = GA.getName();
180*5f757f3fSDimitry Andric if (Name.starts_with("llvm.") || (!Name.empty() && Name[0] == 1) ||
1810eae32dcSDimitry Andric IsNameExcluded(Name, ExcludedAliasesPrefixes))
1820b57cec5SDimitry Andric continue;
1830b57cec5SDimitry Andric
1845e801ac6SDimitry Andric GA.setName("alias");
1850b57cec5SDimitry Andric }
1860b57cec5SDimitry Andric
1870b57cec5SDimitry Andric // Rename all global variables
188fe6060f1SDimitry Andric for (GlobalVariable &GV : M.globals()) {
189fe6060f1SDimitry Andric StringRef Name = GV.getName();
190*5f757f3fSDimitry Andric if (Name.starts_with("llvm.") || (!Name.empty() && Name[0] == 1) ||
1910eae32dcSDimitry Andric IsNameExcluded(Name, ExcludedGlobalsPrefixes))
1920b57cec5SDimitry Andric continue;
1930b57cec5SDimitry Andric
194fe6060f1SDimitry Andric GV.setName("global");
1950b57cec5SDimitry Andric }
1960b57cec5SDimitry Andric
1970b57cec5SDimitry Andric // Rename all struct types
1980b57cec5SDimitry Andric TypeFinder StructTypes;
1990b57cec5SDimitry Andric StructTypes.run(M, true);
2000b57cec5SDimitry Andric for (StructType *STy : StructTypes) {
2010eae32dcSDimitry Andric StringRef Name = STy->getName();
2020eae32dcSDimitry Andric if (STy->isLiteral() || Name.empty() ||
2030eae32dcSDimitry Andric IsNameExcluded(Name, ExcludedStructsPrefixes))
204e8d8bef9SDimitry Andric continue;
2050b57cec5SDimitry Andric
2060b57cec5SDimitry Andric SmallString<128> NameStorage;
207e8d8bef9SDimitry Andric STy->setName(
208e8d8bef9SDimitry Andric (Twine("struct.") + renamer.newName()).toStringRef(NameStorage));
2090b57cec5SDimitry Andric }
2100b57cec5SDimitry Andric
2110b57cec5SDimitry Andric // Rename all functions
2120b57cec5SDimitry Andric for (auto &F : M) {
21306c3fb27SDimitry Andric if (ExcludeLibFuncs(F))
2140b57cec5SDimitry Andric continue;
2150b57cec5SDimitry Andric
2160b57cec5SDimitry Andric // Leave @main alone. The output of -metarenamer might be passed to
2170b57cec5SDimitry Andric // lli for execution and the latter needs a main entry point.
21806c3fb27SDimitry Andric if (F.getName() != "main")
2190b57cec5SDimitry Andric F.setName(renamer.newName());
2200b57cec5SDimitry Andric
221e8d8bef9SDimitry Andric MetaRename(F);
2220b57cec5SDimitry Andric }
2230b57cec5SDimitry Andric }
2240b57cec5SDimitry Andric
2250b57cec5SDimitry Andric } // end anonymous namespace
2260b57cec5SDimitry Andric
run(Module & M,ModuleAnalysisManager & AM)227e8d8bef9SDimitry Andric PreservedAnalyses MetaRenamerPass::run(Module &M, ModuleAnalysisManager &AM) {
228e8d8bef9SDimitry Andric FunctionAnalysisManager &FAM =
229e8d8bef9SDimitry Andric AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
230e8d8bef9SDimitry Andric auto GetTLI = [&FAM](Function &F) -> TargetLibraryInfo & {
231e8d8bef9SDimitry Andric return FAM.getResult<TargetLibraryAnalysis>(F);
232e8d8bef9SDimitry Andric };
233e8d8bef9SDimitry Andric MetaRename(M, GetTLI);
234e8d8bef9SDimitry Andric
235e8d8bef9SDimitry Andric return PreservedAnalyses::all();
236e8d8bef9SDimitry Andric }
237